<template>
  <div class="bpmn-designer">
    <div class="toolbar" v-if="!readonly">
      <el-button-group>
        <el-button @click="handleSave" type="primary">
          <el-icon><Download /></el-icon>保存
        </el-button>
        <el-button @click="handleDownload">
          <el-icon><Download /></el-icon>下载
        </el-button>
        <el-button @click="handleImport">
          <el-icon><Upload /></el-icon>导入
        </el-button>
        <el-button @click="showFormDesigner" type="primary">
          <el-icon><Setting /></el-icon>表单设计
        </el-button>
      </el-button-group>
    </div>
    <div class="container">
      <div class="canvas-container">
        <div class="canvas" ref="canvas"></div>
      </div>
      <div class="properties-panel" ref="propertiesPanel" v-if="!readonly"></div>
    </div>
    <input
      type="file"
      ref="fileInput"
      style="display: none"
      accept=".bpmn,.xml"
      @change="onFileChange"
    />
    <!-- 表单配置对话框 -->
    <el-dialog
      v-model="formConfigVisible"
      title="表单设计"
      width="800px"
      :close-on-click-modal="false">
      <el-form :model="formConfig" label-width="100px">
        <el-form-item>
          <el-button type="primary" @click="addField">
            <el-icon><Plus /></el-icon>添加字段
          </el-button>
        </el-form-item>
        
        <draggable
          v-model="formConfig.fields"
          item-key="tempId"
          handle=".drag-handle"
          ghost-class="ghost"
          @end="updateOrder">
          <template #item="{element, index}">
            <div class="field-item">
              <el-icon class="drag-handle"><Rank /></el-icon>
              <el-form-item label-width="0">
                <el-row :gutter="10">
                  <el-col :span="6">
                    <el-input v-model="element.fieldId" placeholder="字段标识"></el-input>
                  </el-col>
                  <el-col :span="6">
                    <el-input v-model="element.label" placeholder="字段名称"></el-input>
                  </el-col>
                  <el-col :span="6">
                    <el-select v-model="element.type" placeholder="字段类型">
                      <el-option label="文本" value="string"></el-option>
                      <el-option label="数字" value="number"></el-option>
                      <el-option label="日期" value="date"></el-option>
                      <el-option label="用户" value="user"></el-option>
                    </el-select>
                  </el-col>
                  <el-col :span="4">
                    <el-checkbox v-model="element.required">必填</el-checkbox>
                  </el-col>
                  <el-col :span="2">
                    <el-button type="danger" link @click="removeField(index)">
                      <el-icon><Delete /></el-icon>
                    </el-button>
                  </el-col>
                </el-row>
              </el-form-item>
            </div>
          </template>
        </draggable>

        <div v-if="formConfig.fields.length === 0" class="no-fields">
          <el-empty description="暂无字段，点击上方按钮添加" />
        </div>
      </el-form>
      
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="formConfigVisible = false">取消</el-button>
          <el-button type="primary" @click="saveFormConfig">
            确定
          </el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import { 
  Download, 
  Upload, 
  Plus, 
  Delete, 
  Rank,
  Setting
} from '@element-plus/icons-vue'
import BpmnJS from 'bpmn-js/dist/bpmn-modeler.production.min.js'
import 'bpmn-js/dist/assets/diagram-js.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'
import {
  BpmnPropertiesPanelModule,
  BpmnPropertiesProviderModule,
  CamundaPlatformPropertiesProviderModule
} from 'bpmn-js-properties-panel'
import 'bpmn-js-properties-panel/dist/assets/properties-panel.css'
import 'bpmn-js-properties-panel/dist/assets/element-templates.css'
import camundaModdleDescriptor from 'camunda-bpmn-moddle/resources/camunda'
import request from '@/utils/request'
import draggable from 'vuedraggable'
import { getProcessFormConfig, saveProcessFormConfig } from '@/api/process'

const props = defineProps({
  processId: {
    type: String,
    default: ''
  },
  readonly: {
    type: Boolean,
    default: false
  }
})

const emit = defineEmits(['save'])

const canvas = ref(null)
const propertiesPanel = ref(null)
const fileInput = ref(null)
let modeler = null

const loadProcessXml = async () => {
  if (!props.processId) {
    console.warn('processId is undefined');
    return;
  }

  try {
    const response = await request.get(`/process-definitions/xml`, {
      params: { processId: props.processId }
    });
    if (response.data) {
      await modeler.importXML(response.data);
      modeler.get('canvas').zoom('fit-viewport');
    }
  } catch (error) {
    console.error('Error loading process XML:', error);
    ElMessage.error('加载流程图失败');
  }
}

const initBpmn = async () => {
  const modules = [
    BpmnPropertiesPanelModule,
    BpmnPropertiesProviderModule,
    CamundaPlatformPropertiesProviderModule
  ]

  modeler = new BpmnJS({
    container: canvas.value,
    propertiesPanel: {
      parent: propertiesPanel.value
    },
    additionalModules: [
      BpmnPropertiesPanelModule,
      BpmnPropertiesProviderModule,
      CamundaPlatformPropertiesProviderModule
    ],
    moddleExtensions: {
      camunda: camundaModdleDescriptor
    }
  })

  if (props.processId) {
    await loadProcessXml();
  } else if (props.xml) {
    await modeler.importXML(props.xml);
  } else {
    const defaultXml = `<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL"
                  xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
                  xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
                  xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
                  xmlns:camunda="http://camunda.org/schema/1.0/bpmn"
                  id="Definitions_1"
                  targetNamespace="http://bpmn.io/schema/bpmn">
  <bpmn:process id="Process_1" name="新流程" isExecutable="true" camunda:historyTimeToLive="30">
    <bpmn:startEvent id="StartEvent_1" name="开始">
      <bpmn:outgoing>Flow_1</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:endEvent id="EndEvent_1" name="结束">
      <bpmn:incoming>Flow_1</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="Flow_1" sourceRef="StartEvent_1" targetRef="EndEvent_1" />
  </bpmn:process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
      <bpmndi:BPMNShape id="StartEvent_1_di" bpmnElement="StartEvent_1">
        <dc:Bounds x="156" y="81" width="36" height="36" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="163" y="124" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="EndEvent_1_di" bpmnElement="EndEvent_1">
        <dc:Bounds x="392" y="81" width="36" height="36" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="399" y="124" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="Flow_1_di" bpmnElement="Flow_1">
        <di:waypoint x="192" y="99" />
        <di:waypoint x="392" y="99" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>`
    await modeler.importXML(defaultXml);
  }
}

const handleSave = async () => {
  try {
    const { xml } = await modeler.saveXML({ format: true })
    emit('save', xml)
  } catch (err) {
    ElMessage.error('保存失败')
    console.error(err)
  }
}

const handleDownload = async () => {
  try {
    const { xml } = await modeler.saveXML({ format: true })
    const blob = new Blob([xml], { type: 'text/xml' })
    const link = document.createElement('a')
    link.href = window.URL.createObjectURL(blob)
    link.download = 'process.bpmn'
    link.click()
  } catch (err) {
    ElMessage.error('下载失败')
    console.error(err)
  }
}

const handleImport = () => {
  fileInput.value.click()
}

const onFileChange = async (event) => {
  const file = event.target.files[0]
  if (!file) return

  try {
    const xml = await file.text()
    await modeler.importXML(xml)
    modeler.get('canvas').zoom('fit-viewport')
    ElMessage.success('导入成功')
  } catch (err) {
    ElMessage.error('导入失败')
    console.error(err)
  } finally {
    event.target.value = ''
  }
}

watch(
  () => props.processId,
  async (newId) => {
    if (newId && modeler) {
      await loadProcessXml();
      await loadFormConfig();
    }
  },
  { immediate: true }
)

// 表单相关的状态
const formConfigVisible = ref(false)
const formConfig = ref({
  fields: []
})

// 添加字段
const addField = () => {
  if (!formConfig.value.fields) {
    formConfig.value.fields = []
  }
  
  const newField = {
    tempId: Date.now() + Math.random(),  // 确保唯一性
    fieldId: `field_${formConfig.value.fields.length + 1}`,  // 默认字段ID
    label: `字段${formConfig.value.fields.length + 1}`,      // 默认标签
    type: 'string',
    placeholder: '',
    required: false,
    minValue: null,
    maxValue: null,
    orderIndex: formConfig.value.fields.length
  }
  
  formConfig.value.fields.push(newField)
  console.log('Added field:', newField)
  console.log('Current fields:', formConfig.value.fields)
}

// 删除字段
const removeField = (index) => {
  formConfig.value.fields.splice(index, 1)
  updateOrder()
}

// 更新字段顺序
const updateOrder = () => {
  formConfig.value.fields.forEach((field, index) => {
    field.orderIndex = index
  })
}

// 保存表单配置
const saveFormConfig = async () => {
  try {
    const processKey = await getProcessKey();
    if (!processKey) {
      ElMessage.error('获取流程标识失败');
      return;
    }

    // 将表单字段转换为JSON字符串
    const formSchema = JSON.stringify(formConfig.value.fields);
    
    const response = await request.post(`/form-definitions/${processKey}`, formSchema, {
      headers: {
        'Content-Type': 'application/json'
      }
    });

    if (response.data) {
      formConfig.value.fields = response.data.formSchema ? JSON.parse(response.data.formSchema) : [];
      formConfigVisible.value = false;
      ElMessage.success('保存成功');
    }
  } catch (error) {
    console.error('保存表单配置失败:', error);
    ElMessage.error('保存失败');
  }
}

// 加载表单配置
const loadFormConfig = async () => {
  try {
    const processKey = await getProcessKey();
    if (!processKey) {
      console.warn('Process key is null');
      formConfig.value.fields = [];
      return;
    }
    
    const response = await request.get(`/form-definitions/${processKey}`);
    if (response.data && response.data.formSchema) {
      try {
        formConfig.value.fields = JSON.parse(response.data.formSchema);
      } catch (e) {
        console.error('解析表单配置失败:', e);
        formConfig.value.fields = [];
      }
    } else {
      formConfig.value.fields = [];
    }
  } catch (error) {
    console.error('加载表单配置失败:', error);
    ElMessage.error('加载表单配置失败');
    formConfig.value.fields = [];
  }
}

// 获取流程定义key
const getProcessKey = async () => {
  if (!props.processId) return null;
  try {
    // 使用正确的URL格式
    const response = await request.get(`/process-definitions/${encodeURIComponent(props.processId)}`);
    if (response.data) {
      return response.data.key;
    }
    throw new Error('Process definition not found');
  } catch (error) {
    console.error('获取流程定义key失败:', error);
    ElMessage.error('获取流程定义key失败');
    throw error;
  }
}

// 显示表单配置对话框
const showFormDesigner = async () => {
  formConfigVisible.value = true
  await loadFormConfig()  // 等待加载完成
}

onMounted(async () => {
  console.log('Component mounted with processId:', props.processId)
  await initBpmn()
  if (props.processId) {
    await loadFormConfig()
  }
})

onUnmounted(() => {
  if (modeler) {
    modeler.destroy()
  }
})
</script>

<style scoped>
.bpmn-designer {
  height: 100%;
  display: flex;
  flex-direction: column;
  background-color: #fff;
  position: relative;
}

.toolbar {
  padding: 8px;
  border-bottom: 1px solid #dcdfe6;
  background-color: #fff;
  z-index: 10;
  flex-shrink: 0;
}

.container {
  flex: 1;
  display: flex;
  background-color: #fff;
  position: relative;
  overflow: hidden;
  min-height: 0;
}

.canvas-container {
  flex: 1;
  position: relative;
  overflow: hidden;
}

.canvas {
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
}

.properties-panel {
  width: 340px;
  border-left: 1px solid #dcdfe6;
  overflow-y: auto;
  background-color: #fff;
  box-shadow: -2px 0 4px rgba(0, 0, 0, 0.1);
  flex-shrink: 0;
}

.properties-panel::-webkit-scrollbar {
  width: 6px;
}

.properties-panel::-webkit-scrollbar-thumb {
  background-color: #dcdfe6;
  border-radius: 3px;
}

.properties-panel::-webkit-scrollbar-track {
  background-color: #f8f8f8;
}

:deep(.djs-palette) {
  top: 0;
  left: 0;
  width: 100px;
  border-right: 1px solid #dcdfe6;
  background-color: #f8f8f8;
  position: absolute;
  z-index: 10;
}

:deep(.djs-container) {
  width: 100% !important;
  height: 100% !important;
}

:deep(.bjs-powered-by) {
  display: none;
}

:deep(.canvas-parent) {
  width: 100% !important;
  height: 100% !important;
  position: absolute !important;
  left: 0 !important;
  top: 0 !important;
  overflow: hidden !important;
}

:deep(.djs-container svg) {
  width: 100% !important;
  height: 100% !important;
}

.field-item {
  display: flex;
  align-items: center;
  padding: 10px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  margin-bottom: 10px;
}

.drag-handle {
  cursor: move;
  margin-right: 10px;
  color: #909399;
}

.ghost {
  opacity: 0.5;
  background: #c8ebfb;
}

.mt-2 {
  margin-top: 8px;
}

.form-config-btn {
  margin-left: 10px;
}

:deep(.el-dialog__body) {
  max-height: calc(80vh - 120px);
  overflow-y: auto;
}

.field-item {
  background-color: #fff;
  margin-bottom: 10px;
  padding: 15px;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.no-fields {
  text-align: center;
  padding: 20px;
  color: #909399;
}

.field-item {
  background-color: #fff;
  margin-bottom: 10px;
  padding: 15px;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  border: 1px solid #dcdfe6;
}

.field-item:hover {
  border-color: #409eff;
}
</style> 